/*
 * JSF Toolkit Component Framework
 * Copyright (C) 2007 Noah Sloan <iamnoah A-T gmail D0T com>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 */
package com.jsftoolkit.utils;

import java.util.HashMap;
import java.util.Map;

import com.jsftoolkit.utils.Utils.MapBuilder;

/**
 * Utility methods for handling Classes.
 * 
 * @author noah
 * 
 */
public class ClassUtils {

	/**
	 * Map of primitive type classes to their wrapper.
	 */
	@SuppressWarnings("unchecked")
	private static final Map<Class, Class> FROM_PRIMITIVE = MapBuilder
			.putFirst((Class) boolean.class, (Class) Boolean.class).put(
					byte.class, Byte.class).put(short.class, Short.class).put(
					int.class, Integer.class).put(long.class, Long.class).put(
					float.class, Float.class).put(double.class, Double.class)
			.put(char.class, Character.class).put(void.class, Void.class)
			.getMap();

	/**
	 * Returns the wrapper for the given primitive type.
	 * 
	 * @param primitive
	 * @return the wrapper for the given class, or primitive if it is not a
	 *         primitive type.
	 */
	public static Class<?> box(Class<?> primitive) {
		if (primitive == null || !primitive.isPrimitive()) {
			return primitive;
		}
		return FROM_PRIMITIVE.get(primitive);
	}

	private static final Class<?>[] PRIMITIVES = { boolean.class, byte.class,
			short.class, int.class, long.class, float.class, double.class,
			char.class, void.class };

	private static final Map<String, Class<?>> FROM_NAME;

	static {
		FROM_NAME = new HashMap<String, Class<?>>();
		for (Class<?> clazz : PRIMITIVES) {
			FROM_NAME.put(clazz.getName(), clazz);
		}
	}

	/**
	 * 
	 * @param name
	 * @return the primitive class object with the given name.
	 */
	public static Class<?> forPrimitive(String name) {
		return FROM_NAME.get(name);
	}

	/**
	 * 
	 * @param types
	 * @param args
	 * @return true if the class of each of the args can be assigned to the
	 *         corresponding type, or is null.
	 */
	public static boolean typesMatch(Class<?>[] types, Object[] args) {
		if (types.length != args.length) {
			return false;
		}
		int i = 0;
		for (Class<?> type : types) {
			if (args[i] != null && !type.isAssignableFrom(args[i].getClass())) {
				// type doesn't match, skip the method
				return false;
			}
			i++;
		}
		return true;
	}

}
